/*
 * Copyright (C) 2010 Fores Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.fores.midori.xmlrpc;

import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


/**
 * XML-RPCの「array」タグを解析するためのクラス。<br>
 * (このクラスはスレッドセーフではありません。)<br>
 * (ライブラリの使用者には公開したくない内部処理用のクラスなので、あえてパッケージスコープにしています。)<br>
 */
class ArrayParser extends AbstractRecursiveTypeParserImpl {
	//==========================================================
	//フィールド

	/**
	 * 結果を格納するList
	 */
	private List<Object> list = new ArrayList<Object>();


	//==========================================================
	//メソッド

	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//抽象メソッドの実装

	/**
	 * 結果のオブジェクトを追加します。<br>
	 *
	 * @param obj 結果のオブジェクト
	 * @throws SAXException SAX例外
	 */
	@Override
	protected void addResult(Object obj) throws SAXException {
		//引数のオブジェクトをフィールドのListに追加する
		this.list.add(obj);
	}


	//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
	//オーバーライドするメソッド

	/**
	 * 要素の開始通知を受け取ります。<br>
	 *
	 * @param uri 名前空間URI
	 * @param localName 前置修飾子を含まないローカル名
	 * @param qName 接頭辞を持つ修飾名
	 * @param attributes 要素に付加された属性
	 * @throws SAXException SAX例外
	 */
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		//タグの階層レベルを+1する
		this.level++;

		//階層レベルが1の場合
		if (this.level == 1) {
			//名前空間URIの指定無しの「array」タグ以外の場合
			if (!(isBlank(uri) && "array".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「array」タグが開始されるべきところで、別のタグが開始されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}
		}
		//階層レベルが2の場合
		else if (this.level == 2) {
			//名前空間URIの指定無しの「data」タグ以外の場合
			if (!(isBlank(uri) && "data".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「data」タグが開始されるべきところで、別のタグが開始されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}
		}
		//階層レベルが3の場合
		else if (this.level == 3) {
			//名前空間URIの指定無しの「value」タグ以外の場合
			if (!(isBlank(uri) && "value".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「value」タグが開始されるべきところで、別のタグが開始されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}

			//「value」タグの開始時の処理を呼び出す
			startValueTag();
		}
		//それ以外の場合
		else {
			//親クラスの処理を呼び出す
			super.startElement(uri, localName, qName, attributes);
		}
	}

	/**
	 * 要素の終了通知を受け取ります。<br>
	 *
	 * @param uri 名前空間URI
	 * @param localName 前置修飾子を含まないローカル名
	 * @param qName 接頭辞を持つ修飾名
	 * @throws SAXException SAX例外
	 */
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		//階層レベルが1の場合
		if (this.level == 1) {
			//名前空間URIの指定無しの「array」タグ以外の場合
			if (!(isBlank(uri) && "array".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「array」タグが終了されるべきところで、別のタグが終了されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}

			//フィールドのListを結果のオブジェクトとして設定する
			setResult(this.list);
		}
		//階層レベルが2の場合
		else if (this.level == 2) {
			//名前空間URIの指定無しの「data」タグ以外の場合
			if (!(isBlank(uri) && "data".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「data」タグが終了されるべきところで、別のタグが終了されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}
		}
		//階層レベルが3の場合
		else if (this.level == 3) {
			//名前空間URIの指定無しの「value」タグ以外の場合
			if (!(isBlank(uri) && "value".equals(localName))) {
				//例外を投げる
				throw new SAXParseException("「value」タグが終了されるべきところで、別のタグが終了されました。"
						+ new QName(uri, localName), getDocumentLocator());
			}

			//「value」タグの終了時の処理を呼び出す
			endValueTag();
		}
		//それ以外の場合
		else {
			//親クラスの処理を呼び出す
			super.endElement(uri, localName, qName);
		}

		//タグの階層レベルを-1する
		this.level--;
	}

}
